﻿\subsection{进程、线程的创建}

\subsubsection{\texttt{System} 进程与其主线程 }

线（进）程创建的过程本质上是创建线（进）程控制块的过程，该过程由一个已经存在的执行流完成，也即需要在一个已经存在的线程中创建新的线（进）程，初始的操作系统内核中并不存在线程。
不过，操作系统内核启动后，CPU 上执行的内核代码就是初始的执行流，但这条执行流并没有相应的线程控制块。
线程的本质是执行流，将这条执行流进行封装，使其成为内核中的第一条线程。由这条线程可创建出新的进程和线程。
根据进程与线程之间的关系划分，第一条线程应作为主线程存在于一个进程中，SimpleOS 将该进程称作 \lstinline{System} 进程。

\subsubsection{创建线程}

在当前进程中创建一个线程相对较为容易，只需要为新的线程分配内核栈和用户栈，指定线程的入口地址即可。新线程的控制块在创建后移入线程调度队列。

\subsubsection{创建进程}

在创建进程时，需要为进程创建一条主线程用于运行。
此外，还需要为进程创建独立的内存空间，分配内存堆，将进程的可执行文件从磁盘调入内存。
创建独立的内存空间本质上即为进程创建页目录，页目录的内核空间与内核页目录保持一致，用户空间则根据创建进程的实际要求确定。
鉴于对进程用户空间的操作需要在进程空间中完成，这意味着页目录寄存器需引用新进程的页目录，这会给当前线程的执行带来影响。
为此，SimpleOS 将创建进程的过程分为两步，在当前线程（图 \ref{CREATE_PROCESS_0}）和由当前线程创建的新进程的主线程（图 \ref{CREATE_PROCESS_1}）中完成：

在当前线程中，完成如下的步骤：

\lstset {
    basicstyle = \bfseries\zihao{-5}\ttfamily\linespread{1.5}
}
\begin{enumerate}
    \item[（1）] 为新进程创建进程控制块，调整进程树的逻辑关系。
    \item[（2）] 为新进程创建页目录，页目录物理地址保存到新进程控制块中。
    \item[（2）] 为新进程创建主线程，并分配内核栈（用户栈不分配），入口地址统一为 \lstinline{InitializeMainThread}。
    \item[（3）] 将新进程的主线程添加到线程调度队列。
\end{enumerate}

\begin{figure}[h!]
    \Centering
    \caption{创建进程（一）}
    \label{CREATE_PROCESS_0}
    \includegraphics[scale=0.6]{build/Paper/Assets/CreateProcess_00.pdf}
\end{figure}

随后，调度器将新线程调度上处理器执行 \lstinline{InitializeMainThread} 函数，此函数中完成创建新进程的剩余工作：

\lstset {
    basicstyle = \bfseries\zihao{5}\ttfamily\linespread{1.5}
}

\begin{enumerate}
    \item[（1）] 将进程的可执行文件映像从磁盘读入内存并解析。
    \item[（2）] 为当前进程创建内存堆。
    \item[（3）] 为线程自身分配用户栈。
    \item[（4）] 初始化用户程序运行环境，构造中断现场并转入用户态执行用户程序。
\end{enumerate}

\begin{figure}[h!]
    \Centering
    \caption{创建进程（二）}
    \label{CREATE_PROCESS_1}
    \includegraphics[scale=0.8]{build/Paper/Assets/CreateProcess_01.pdf}
\end{figure}
